package com.file.system.plugin.shiro;

import com.file.system.plugin.shiro.filter.ShiroLoginFilter;
import com.file.system.tools.console.Read;
import org.apache.commons.codec.binary.Base64;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * @author jch
 * @Description (shiro)
 * @date
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiro = new ShiroFilterFactoryBean();
        shiro.setSecurityManager(securityManager);
        shiro.setUnauthorizedUrl("/not/auth");

        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("roleOrFilter", new RoleOrFilter());
        filterMap.put("authc", new ShiroLoginFilter());
        shiro.setFilters(filterMap);

        Map<String, String> chainMap = new LinkedHashMap<>();

        // 系统菜单节点权限------------------------------------------------------------------------------------------------
        customRealm().initMenuAuth(chainMap);
        // 加载需放行路径--------------------------------------------------------------------------------------------------
        customRealm().getAnonPath().forEach(anonPath -> {
            chainMap.put(anonPath, "anon");
        });
        // 退出----------------------------------------------------------------------------------------------------------
        chainMap.put("/logout", "logout");
        // 其他权限-------------------------------------------------------------------------------------------------------
        chainMap.put("/**", customRealm().getAllAuth());
        shiro.setFilterChainDefinitionMap(chainMap);
        Read.console("shiro");
        return shiro;
    }

    /**
     * 创建EhCacheManager对象，并设置ehcache-shiro.xml配置文件
     */
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:shiro/ehcache-shiro.xml");
        return cacheManager;
    }


    /**
     * 创建shiro的SecurityManager
     */
    @Bean
    public SecurityManager shiroSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(customRealm());
        //配置seesion
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }


    /**
     * 创建自定义Realm
     */
    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        // 设置缓存
        customRealm.setCachingEnabled(true);
        // 设置认证缓存
        customRealm.setAuthenticationCachingEnabled(true);
        // 设置认证缓存名称
        customRealm.setAuthenticationCacheName("authenticationCache");
        // 设置授权缓存
        customRealm.setAuthorizationCachingEnabled(true);
        // 设置授权缓存名称
        customRealm.setAuthorizationCacheName("authorizationCache");
        return customRealm;
    }

    /**
     * 创建ShiroSessionListener对象
     */
    @Bean
    public ShiroSessionListener sessionListener() {
        ShiroSessionListener sessionListener = new ShiroSessionListener();
        return sessionListener;
    }

    /**
     * 返回一个SessionIdGenerator对象，用于生成SessionId
     */
    @Bean
    public SessionIdGenerator sessionIdGenerator() {
        return new JavaUuidSessionIdGenerator();
    }


    /**
     * 创建EnterpriseCacheSessionDAO对象
     */
    @Bean
    public SessionDAO sessionDAO() {
        EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
        //使用ehCacheManager
        enterpriseCacheSessionDAO.setCacheManager(ehCacheManager());
        //设置session缓存的名字 默认为 shiro-activeSessionCache
        enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        //sessionId生成器
        enterpriseCacheSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        return enterpriseCacheSessionDAO;
    }


    /**
     * shiro session的管理
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();

        // 设置会话超时时间
        sessionManager.setGlobalSessionTimeout(120 * 60 * 1000);
        // 设置会话监听器
        sessionManager.setSessionListeners(Arrays.asList(sessionListener()));
        // 设置是否重写会话IDURL
        sessionManager.setSessionIdUrlRewritingEnabled(false);

        // 设置记住我Cookie
        sessionManager.setSessionIdCookie(rememberMeCookie());
        // 设置会话验证间隔
        sessionManager.setSessionValidationInterval(5 * 60 * 1000);

        // 设置会话DAO
        sessionManager.setSessionDAO(sessionDAO());

        return sessionManager;
    }

    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie cookie = new SimpleCookie("system.session");
        //设置cookie只读
        cookie.setHttpOnly(true);
        //设置cookie路径
        /*cookie.setPath("/");*/
        //设置cookie有效期
        cookie.setMaxAge(60 * 60 * 1000);
        return cookie;
    }

    /**
     * 获取MethodInvokingFactoryBean实例
     */
    @Bean
    public MethodInvokingFactoryBean getMethodInvokingFactoryBean() {
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        //设置静态方法
        factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        //设置参数
        factoryBean.setArguments(new Object[]{shiroSecurityManager()});
        return factoryBean;
    }


    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        // 设置代理类
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        // 设置代理类
        creator.setProxyTargetClass(true);
        return creator;
    }


    /**
     * 创建一个AuthorizationAttributeSourceAdvisor对象，并设置SecurityManager
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


   @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        // 设置cookie
        cookieRememberMeManager.setCookie(rememberMeCookie());
        // 设置加密密钥
        cookieRememberMeManager.setCipherKey(Base64.decodeBase64(generateNewKey()));
        return cookieRememberMeManager;
    }

    /**
     * 随机秘钥
     */
    private String generateNewKey() {
        try {
            // 获取AES算法密钥
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            SecretKey deskey = keygen.generateKey();
            // 返回Base64编码的密钥
            return Base64.encodeBase64String(deskey.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
            return "7Iqlf6Ql/A4h7Umjw+254w==";
        }
    }

}
